<html lang="zh-CN">
<head>
  <meta charset="utf-8">
  <title>文档</title>
  <link href="./css/semantic/semantic.min.css" rel="stylesheet">
  <link href="./css/oscTree.css" rel="stylesheet">
  <link href="./css/markdown.css" rel="stylesheet">
  <link href="./css/index.css" rel="stylesheet">
</head>
<body>
  <div class="ui container">
    <div id="project-title">
      <div class="title-wrap">
        <div class="left">
          <i class="icon eye"></i>
          文档预览:
          <span id="preview-title"></span>
        </div>
   
      </div>
    </div>

    <div class="ui container" id="wiki-preview-container">
      <div id="wiki-preview">
        <div class="ui segment">
          <div class="ui grid page">
            <div class="three wide column doc-list">
              <div class="title">
                <a id="ex-all">
                  收缩全部章节
                </a>
              </div>
              <div class="ztree" id="tree"></div>
            </div>
            <div class="thirteen wide column doc-content">
              <div id="page-detail">
                <div class="title">
                </div>
                <div class="content markdown-body">
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>
      </div>
  </div>
</body>
</html>
<script src="./js/jquery.min.js"></script>
<script src="./js/ztree.all.js"></script>
<script src="./js/jquery.ztree.exhide.min.js"></script>
<script>
  var zTreeObj;var expandStatus=true;$(document).ready(function(){var setting={view:{showLine:true,showIcon:true},callback:{onClick:function(e,treeId,treeNode){if(treeNode!==null&&!treeNode.isParent&&typeof(treeNode.children)==="undefined"){var sort_id=treeNode.sort_id;var content=json_data.content;for(var c in content){if(c==sort_id){$("#page-detail .title").html(treeNode.name);$("#page-detail .content").html(content[c]);return false}}}else{zTreeObj.expandNode(treeNode)}}},data:{simpleData:{enable:true}}};zTreeObj=$.fn.zTree.init($("#tree"),setting,json_data.title);var first_content=json_data.title[0];$("#page-detail .title").html(first_content.name);$("#page-detail .content").html(json_data.content[first_content.sort_id]);$("#preview-title").html(json_data.preview_title);$("#ex-all").on("click",function(e){zTreeObj.expandAll(!expandStatus);expandStatus=!expandStatus;if(expandStatus){$(this).text("收缩全部章节")}else{$(this).text("展开全部章节")}})});
</script><script>var json_data = {"preview_title":"HServer-JAVA","title":[{"id":"0000000000001，注解认识","pId":0,"name":"1，注解认识","parent":null,"order":1,"sort_id":1963855,"extname":".md","isParent":false,"isHidden":false,"content":"\u003Ch5\u003E\n\u003Ca id=\"为了让开发者快速理解和使用hserver将大部分的注解定义的名字和spring相似这样让开发者可以快熟理解和使用\" class=\"anchor\" href=\"#%E4%B8%BA%E4%BA%86%E8%AE%A9%E5%BC%80%E5%8F%91%E8%80%85%E5%BF%AB%E9%80%9F%E7%90%86%E8%A7%A3%E5%92%8C%E4%BD%BF%E7%94%A8hserver%E5%B0%86%E5%A4%A7%E9%83%A8%E5%88%86%E7%9A%84%E6%B3%A8%E8%A7%A3%E5%AE%9A%E4%B9%89%E7%9A%84%E5%90%8D%E5%AD%97%E5%92%8Cspring%E7%9B%B8%E4%BC%BC%E8%BF%99%E6%A0%B7%E8%AE%A9%E5%BC%80%E5%8F%91%E8%80%85%E5%8F%AF%E4%BB%A5%E5%BF%AB%E7%86%9F%E7%90%86%E8%A7%A3%E5%92%8C%E4%BD%BF%E7%94%A8\"\u003E\u003C/a\u003E为了让开发者快速理解和使用HServer，将大部分的注解定义的名字和Spring相似，这样让开发者可以快熟理解和使用.\u003C/h5\u003E\n\u003Cpre\u003E\u003Ccode\u003E@Bean\n将Bean对象加入IOC容器中比如\n    //默认按类型加入IOC容器\n    @Bean\n    class TestService{}\n    //指定名字加入容器，装配的时候就只能通过名字装配了\n    @Bean(\"testService1\")\n    class Test{}\n    \n    \n@Autowired\n自动装配注解\n    //按类型注入\n    @Autowired\n    private TestService testService;\n    //按Bean名字注入\n    @Autowired(\"testServer1\")\n    private TestService testService; \n    \n       \n@Controller\n控制器注解，将控制器加入IOC容器中，类似Spring mvc\n注解在类上面直接加上即可比如\n    //Index控制器\n    @Controller\n    class IndexController{}\n    //value 会自动补全类中的url定义的URL，name值在鉴权中和APi文档生成时可以提取当前模块名\n    //如果不写name值，name将会自动使用包名代替\n    @Controller(value = \"/v1/Api2\", name = \"Api接口2\")\n    class IndexController{}\n       \n@GET,@POST,@RequestMapping\n方法注解，在@Controller注解类类中使用，标注一个方法为GET或者POST方法，例如\n    @GET(\"/index\")\n    public void index(){}  \n    @POST(\"/index\")\n    public void index(){}\n    \n    //url规则匹配\n    @GET(\"/url1/{url}\")\n    public String url(HttpRequest httpRequest){\n        String url = httpRequest.query(\"url\");\n        System.out.println(url);\n        return url;\n    }\n\n    @GET(\"/url/{url}\")\n    public String url(String url){\n        return \"匹配到的URL:\"+url;\n    }\n\n    @POST(\"/a/{url}/bb\")\n    public String ab(String url){\n        return \"匹配到的URL:\"+url;\n    } \n     \n    //2.9.4+以上支持\n    @RequestMapping(value = \"/PUT\", method = RequestMethod.PUT)\n    public JsonResult PUT() {\n      return JsonResult.ok();\n    }\n    //2.9.4+以上支持\n    @RequestMapping(value = \"/get_post\", method = {RequestMethod.POST,RequestMethod.GET})\n    public JsonResult get_post() {\n      return JsonResult.ok();\n    }\n    \n    //2.9.4+以上支持\n    //全类型\n    @RequestMapping(value = \"/all\")\n    public JsonResult all() {\n      return JsonResult.ok();\n    }\n\n    \n@Filter\n拦截器注解，标注一个类为拦截器，和JavaEE的Filter类似\n    @Filter(1)//1表示拦截优先级，越小越优先\n    public class MyFilter1 implements FilterAdapter {}\n    //需要实现FilterAdapter接口\n    \n    \n@Hook\nhook注解就是Aop\n    @Hook(value = Test.class, method = \"show\")\n    public class HookTest implements HookAdapter {}\n    //value表示aop的类,method要hook的方法，必须实现HookAdapter\n    \n    \n@Task\n 定时任务\n    @Task(name = \"测试定时任务Cron\", time =\"*/5 * * * * ?\")\n    //标记在方法上，同时该类需要被@Bean 标记\n    @Task(name = \"测试定时任务1\", time =\"2000\")\n    public void timerTask() {}\n    \n    \n@WebSocket\n实现websocket通信\n    @WebSocket(\"/ws\")\n    public class WebSocketTest implements WebSocketHandler {}\n    //这样就可以完成基本的通信了\n    \n    \n@Configuration\n自定配置注解，需要配合@Bean注解一起使用，最后会把方法里面的返回的对象\n存储到IOC容器中，同时可以通过Autowired注解注入\n    @Configuration\n    public class DataConfig {\n    \n        //自定义名字（用例：比如多数据源注入）\n        @Bean(\"createUser\")\n        public User createUser(){\n            User user = new User();\n            user.setAge(999);\n            user.setName(\"我是配置类自定义名字的数据\");\n            user.setSex(\"未知\");\n            return user;\n        }\n    \n       //按类型存储 \n        @Bean\n        public User createUser1(){\n            User user = new User();\n            user.setAge(999);\n            user.setName(\"我是配置类的默认数据\");\n            user.setSex(\"未知\");\n            return user;\n        }\n    \n    }\n    \n    \n@RpcService\n标注一个Bean对象是一个rpc服务,也可以分配一个名字\n    @Bean\n    @RpcService\n    public class RpcServiceTest {\n        public String test(String name){\n            return name+\"我是RPC\";\n        }\n    }  \n    \n    \n@Resource\n注入一个Rpc服务，也可以通过名字注入。详情，请看文档介绍   \n    @Resource\n    private RpcServiceTest rpcServiceTest;\n    \n    \n@Sign(\"MD5\")\n@RequiresRoles(\"角色\")\n@RequiresPermissions(value = {\"/权限1\",\"/权限2\"}, logical=Logical.OR)\n该注解用于标注控制器里面的方法，方便自己实现sign签名算法，\n角色检查，权限检查，实现token等，详情下面的对应接口。\n\n\n@BeetlSQL\n该注解实现对Beetlsql的getMpper方法做了一个封装，\n你只需要在mapper中加入该注解，然后进行装配到Service就可以了，\n详情可以参考官方放在的例子\n\u003C/code\u003E\u003C/pre\u003E"},{"id":"0000000000002，完成Hello World项目","pId":0,"name":"2，完成Hello World项目","parent":null,"order":2,"sort_id":1963857,"extname":".md","isParent":false,"isHidden":false,"content":"\u003Cp\u003E#第一步pom依赖引入\u003C/p\u003E\n\u003Cpre\u003E\u003Ccode\u003E\u0026lt;dependency\u0026gt;\n    \u0026lt;groupId\u0026gt;cn.hserver\u0026lt;/groupId\u0026gt;\n    \u0026lt;artifactId\u0026gt;HServer\u0026lt;/artifactId\u0026gt;\n    \u0026lt;version\u0026gt;最新版\u0026lt;/version\u0026gt;\n\u0026lt;/dependency\u0026gt;\n\npublic class WebApp {\n    public static void main(String[] args) {\n        //运行官方例子,直接运行既可以了，默认自带了一些例子。\n        HServerApplication.run(TestWebApp.class, 8888);\n    }\n}\n\n\n#第二步搞一个主函数\npublic class WebApp {\n    public static void main(String[] args) {\n        HServerApplication.run(WebApp.class, 8888);\n    }\n}\n\n#第三步同主函数建立一个包文件夹比如controller\n\n@Controller\npublic class Hello {\n\n    @GET(\"/hello\")\n    public Map index(HttpRequest request, String name) {\n        Map\u0026lt;String, Object\u0026gt; res = new HashMap\u0026lt;\u0026gt;();\n        res.put(\"code\", 200);\n        res.put(\"res\", request.getRequestParams());\n        res.put(\"msg\", \"Hello\");\n        return res;\n    }\n    \n    /**\n     * 模板测试\n     * @param httpResponse\n     */\n    @GET(\"/template\")\n    public void template(HttpResponse httpResponse) {\n        User user = new User();\n        user.setAge(20);\n        user.setName(\"xx\");\n        user.setSex(\"男\");\n        Map\u0026lt;String,Object\u0026gt; obj=new HashMap\u0026lt;\u0026gt;();\n        obj.put(\"user\",user);\n//        httpResponse.sendTemplate(\"/admin/user/list.ftl\", obj);\n        httpResponse.sendTemplate(\"a.ftl\", obj);\n    }\n}\n#就这样你就完成了一个简单得get请求定义，更多例子，可以参考包top.test下面的例子\n\u003C/code\u003E\u003C/pre\u003E"},{"id":"0000000000003，文件上传下载操作","pId":0,"name":"3，文件上传下载操作","parent":null,"order":3,"sort_id":1963858,"extname":".md","isParent":false,"isHidden":false,"content":"\u003Cpre\u003E\u003Ccode\u003E    #File类型得\n    @GET(\"/downFile\")\n    public void downFile(HttpRequest request, HttpResponse response) {\n      response.setDownloadFile(new File(\"D:\\\\Java\\\\HServer\\\\README.md\"));\n    }\n\n    #InputStream 类型得\n    @GET(\"/downInputStream\")\n    public void downInputStream(HttpRequest request, HttpResponse response) throws Exception {\n      File file = new File(\"D:\\\\Java\\\\HServer\\\\README.md\");\n      InputStream fileInputStream = new FileInputStream(file);\n      response.setDownloadFile(fileInputStream,\"README.md\");\n    }\n\n    @POST(\"/file\")\n    public Map file(HttpRequest request) {\n        //单个文件\n          FileItem file = request.queryFile(\"file\");\n          //多个文件上传\n          Map\u0026lt;String, FileItem\u0026gt; fileItems = request.getFileItems();\n      //然后对FileItem 进行保存，就可以了\n      }\n\u003C/code\u003E\u003C/pre\u003E"},{"id":"0000000000004，Aop操作","pId":0,"name":"4，Aop操作","parent":null,"order":4,"sort_id":1963860,"extname":".md","isParent":false,"isHidden":false,"content":"\u003Cp\u003E#必须实现HookAdapter的接口\u003C/p\u003E\n\u003Cpre\u003E\u003Ccode\u003E#同时被@Hook注解标注\n\n@Slf4j\n\n@Hook(value = Test.class, method = \"show\")\n\npublic class HookTest implements HookAdapter {\n\n\n\n    @Override\n\n    public void before(Object[] objects) {\n\n        log.info(\"aop.-前置拦截：\" + objects[0]);\n\n        objects[0]=\"666\";\n\n    }\n\n\n\n    @Override\n\n    public Object after(Object object) {\n\n        return object + \"aop-后置拦截\";\n\n    }\n\n}\n\u003C/code\u003E\u003C/pre\u003E"},{"id":"0000000000005，Filter操作","pId":0,"name":"5，Filter操作","parent":null,"order":5,"sort_id":1963864,"extname":".md","isParent":false,"isHidden":false,"content":"\u003Cp\u003E#必须实现FilterAdapter接口，同时被@Filter标注，数字越小，优先级越高，切不要重复\u003C/p\u003E\n\u003Cpre\u003E\u003Ccode\u003E@Slf4j\n\n@Filter(1)\n\npublic class MyFilter2 implements FilterAdapter {\n\n    @Override\n\n    public void doFilter(FilterChain chain, Webkit webkit) {\n\n        log.info(\"MyFilter-\u0026gt;1\");\n\n        chain.doFilter(webkit);\n\n    }\n\n}\n\u003C/code\u003E\u003C/pre\u003E"},{"id":"0000000000006，定时任务操作","pId":0,"name":"6，定时任务操作","parent":null,"order":6,"sort_id":1963867,"extname":".md","isParent":false,"isHidden":false,"content":"\u003Cpre\u003E\u003Ccode\u003E#需要被@Bean注解标注,可以通过TaskManager类进行定时任务的控制，动态添加和删除\n@Bean\npublic class TaskTest {\n    \n    @Autowired\n    private TestService testService;\n\n    private boolean flag = true;\n\n    public void dynamicAddTimer() {\n        System.out.println(\"动态添加定时任务\");\n        TaskManager.addTask(\"测试任务2\", \"2000\", TestTask.class,\"666\");\n    }\n    \n    \n    @Task(name = \"测试定时任务1\", time =\"*/5 * * * * ?\")\n    public void timerTask() {\n        System.out.println(\"测试定时任务，注入的对象调用结果:\" + testService.testa());\n        if (flag) {\n            dynamicAddTimer();\n            flag = false;\n        }\n    }\n\n    @Task(name = \"测试定时任务2\", time = \"2000\")\n    public void removeTask() {\n        //干掉方法注解版本\n        boolean task1 = TaskManager.removeTask(\"测试定时任务1\");\n        //干掉动态添加的\n        boolean task2 = TaskManager.removeTask(\"测试任务2\");\n        //干掉自己\n        boolean task3 = TaskManager.removeTask(\"测试定时任务2\");\n        //结果\n        System.out.println(\"任务已经被干掉了 tash1=\" + task1 + \",task2=\" + task2 + \",task3=\" + task3);\n    }\n\n}\n\n//动态添加定时任务的实现类必须要实现一个TaskJob,样才能被TaskManager管理\n//添加任务 TaskManager.addTask(\"测试任务2\", \"2000\", TestTask.class,\"666\");\n//删除任务  boolean is_success = TaskManager.removeTask(\"测试任务2\");\npublic class TestTask implements TaskJob {\n\n    @Override\n    public void exec(Object... args) {\n        String args_ = \"\";\n        for (Object arg : args) {\n            args_ += arg.toString();\n        }\n        System.out.println(\"测试定时器动态添加任务，参数是：\" + args_);\n    }\n}\n\u003C/code\u003E\u003C/pre\u003E"},{"id":"0000000000007，websocket操作","pId":0,"name":"7，websocket操作","parent":null,"order":7,"sort_id":1963889,"extname":".md","isParent":false,"isHidden":false,"content":"\u003Cpre\u003E\u003Ccode\u003E#需要被@WebSocket标注同时给一个连接地址，最后实现WebSocketHandler接口，\n#Ws类定义了简单的发送方法，如果有其他的业务操作，可以获取ChannelHandlerContext，进行操作\n\n@WebSocket(\"/ws\")\npublic class WebSocketTest implements WebSocketHandler {\n\n    @Autowired\n    private TestService testService;\n\n    @Override\n    public void onConnect(Ws ws) {\n        System.out.println(\"连接成功,分配的UID：\" + ws.getUid());\n    }\n\n    @Override\n    public void onMessage(Ws ws) {\n        ws.send(\"666\" + testService.testa() + ws.getUid());\n        System.out.println(\"收到的消息,\"+ws.getMessage()+\",UID：\" + ws.getUid());\n    }\n\n    @Override\n    public void disConnect(Ws ws) {\n        System.out.println(\"断开连接,UID:\" + ws.getUid());\n    }\n}\n\u003C/code\u003E\u003C/pre\u003E"},{"id":"0000000000008，自带监控操作","pId":0,"name":"8，自带监控操作","parent":null,"order":8,"sort_id":1963890,"extname":".md","isParent":false,"isHidden":false,"content":"\u003Cpre\u003E\u003Ccode\u003Eapplication.properties文件配置\n    #开启访问统计\n    statistics=true\n    #统计规则:以逗号分割的正则表达式\n    statisticalRules=/hel.*,/admin/.*\n#StatisticsHandler操作\n    #获取所有的IP地址\n    StatisticsHandler.getIpMap()\n    #请求队列（调用的URI，(发送大小，接收大小)宽带监视，耗时时间）\n    StatisticsHandler.getLogRequestQue()\n    #唯一IP请求的数量 uv\n    StatisticsHandler.getUniqueIpCount()\n    #请求总数   pv\n    StatisticsHandler.getCount()\n    #uri记录 被访问的记录（）\n    StatisticsHandler.getUriData()\n#提示：\n1，如果自己要做统计，完全可以自定义一个定时器，动态保存数据哦\n2，StatisticsHandler,提供了一个remove方法,remove，用来清除，或者保存数据用，它会返回一个最新的数据同时清除自己\n3，如果开启统计，请务必，执行Remove方法，不然，内存可能就会蹦\n\u003C/code\u003E\u003C/pre\u003E"},{"id":"0000000000009，全局异常处理","pId":0,"name":"9，全局异常处理","parent":null,"order":9,"sort_id":1963891,"extname":".md","isParent":false,"isHidden":false,"content":"\u003Cpre\u003E\u003Ccode\u003E类必须要被@Bean注解，同时实现GlobalException接口，\n一个项目中最多只有一个GlobalException实现哦，可以没有.没有异常处理，同时又报错了，那么直接显示错误\n@Bean\npublic class WebException implements GlobalException {\n\n    @Override\n    public void handler(Exception exception, Webkit webkit) {\n        exception.printStackTrace();\n        System.out.println(webkit.httpRequest.getUri() + \"---\u0026gt;\" + exception.getMessage());\n        webkit.httpResponse.sendHtml(\"全局异常处理\");\n    }\n}\n\u003C/code\u003E\u003C/pre\u003E"},{"id":"00000000000010，服务器启动完成是执行的方法","pId":0,"name":"10，服务器启动完成是执行的方法","parent":null,"order":10,"sort_id":1963892,"extname":".md","isParent":false,"isHidden":false,"content":"\u003Cpre\u003E\u003Ccode\u003E 类必须要被@Bean注解，同时实现InitRunner接口，\n @Bean\n public class RunInit implements InitRunner {\n \n     @Autowired\n     private User user;\n \n     @Override\n     public void init(String[] args) {\n         System.out.println(\"初始化方法：注入的User对象的名字是--\u0026gt;\"+user.getName());\n     }\n }\n\u003C/code\u003E\u003C/pre\u003E"},{"id":"00000000000011，鉴权认证相关操作","pId":0,"name":"11，鉴权认证相关操作","parent":null,"order":11,"sort_id":1963893,"extname":".md","isParent":false,"isHidden":false,"content":"\u003Cpre\u003E\u003Ccode\u003E//请使用相关注解对控制器的方法做标记，这样在执行到被注解标记的方法就会执行下面的相关方法\n//  List\u0026lt;RouterPermission\u0026gt; routerPermissions = PermissionAdapter.getRouterPermissions();\n// 通过上面的代码可以获取到所有标记的注解，他可以干嘛？\n// 同步后台数据库里面的权限，后台管理面里面可以动态给角色分配权限。\n// 自己做一个下拉选择列表，创建角色分配权限时，多选即可。\n\n/**\n * 验证逻辑请自己实现哦\n */\n@Bean\npublic class TestPermission implements PermissionAdapter {\n\n    @Override\n    public void requiresPermissions(RequiresPermissions requiresPermissions, Webkit webkit) {\n        //这里你可以实现一套自己的权限检查算法逻辑，判断，\n        //如果满足权限，不用其他操作，如果不满足权限，那么你可以通过，Webkit里面的方法直接输出相关内容\n        //或者自定义一个异常类，在全局异常类做相关操作\n        System.out.println(requiresPermissions.value()[0]);\n    }\n\n    @Override\n    public void requiresRoles(RequiresRoles requiresRoles, Webkit webkit) {\n        //这里你可以实现一套自己的角色检查算法逻辑，判断，\n        //其他逻辑同上\n        System.out.println(requiresRoles.value()[0]);\n    }\n\n    @Override\n    public void sign(Sign sign, Webkit webkit) {\n       //这里你可以实现一套自己的接口签名算法检查算法逻辑，判断，\n       //其他逻辑同上\n       Map\u0026lt;String, String\u0026gt; requestParams = webkit.httpRequest.getRequestParams();\n       String sign1 = webkit.httpRequest.getHeader(\"sign\");\n       System.out.println(sign.value());\n    }\n}\n\u003C/code\u003E\u003C/pre\u003E"},{"id":"00000000000012，RPC调用","pId":0,"name":"12，RPC调用","parent":null,"order":12,"sort_id":1963895,"extname":".md","isParent":false,"isHidden":false,"content":"\u003Cp\u003E依赖版本要大于等于2.5版本\n要有主节点\n要有从节点\n主从节点共用接口层\n源码例子（请看gitees的rpc项目）\n举栗子\u003C/p\u003E\n\u003Cp\u003E1.主节点\u003C/p\u003E\n\u003Cpre\u003E\u003Ccode\u003E    #-----------------集群-------------\n    #是否开启集群模式\n    app.cloud.open=true\n    #集群名字\n    app.cloud.name=ServerA\n    #是否是主机\n    app.cloud.master.open=true\n\n    @Resource\n    private RpcService rpcService;\n    @Resource(\"rpc\")\n    private RpcService rpcService;\n\u003C/code\u003E\u003C/pre\u003E\n\u003Cp\u003E2.从节点\u003C/p\u003E\n\u003Cpre\u003E\u003Ccode\u003E    #-----------------集群-------------\n    #是否开启集群模式\n    app.cloud.open=true\n    #集群名字\n    app.cloud.name=ServerB\n    #是否是从机\n    app.cloud.slave.open=true\n    #从机连接主机的IP地址\n    app.cloud.slave.master.host=127.0.0.1\n\n    @Bean\n    @RpcService\n    public class RpcServiceImp implements RpcService{\n        public String test(String name){\n            return name+\"我是RPC\";\n        }\n    }\n\n    @Bean\n    @RpcService(\"rpc\")\n    public class RpcServiceImp implements RpcService{\n        public String test(String name){\n            return name+\"我是RPC\";\n        }\n    }\n\u003C/code\u003E\u003C/pre\u003E\n\u003Cp\u003E可以多从机注册到同一个主机上，调用轮训负载均衡调用。启动主机，在启动从机，从机自动连接主机断开也会自动重新连接\u003C/p\u003E"},{"id":"00000000000013，细节和注意事项","pId":0,"name":"13，细节和注意事项","parent":null,"order":13,"sort_id":1963904,"extname":".md","isParent":false,"isHidden":false,"content":"\u003Ch3\u003E\n\u003Ca id=\"在controller层中定义的方法\" class=\"anchor\" href=\"#%E5%9C%A8controller%E5%B1%82%E4%B8%AD%E5%AE%9A%E4%B9%89%E7%9A%84%E6%96%B9%E6%B3%95\"\u003E\u003C/a\u003E在Controller层中定义的方法\u003C/h3\u003E\n\u003Cp\u003E参数可以是基础数据类型或者bean对象，或者HttpRequest，HttpResponse，（需要是这个包下面的cn.hserver.core.interfaces.的对象）当不是表单提交时，可以通过httpRequest.getRawData()，获取到请求的数据。\u003C/p\u003E\n\u003Ch3\u003E\n\u003Ca id=\"打包jar\" class=\"anchor\" href=\"#%E6%89%93%E5%8C%85jar\"\u003E\u003C/a\u003E打包jar，\u003C/h3\u003E\n\u003Cp\u003E只需要在pom.xml 添加打包命令即可\u003C/p\u003E\n\u003Cpre\u003E\u003Ccode\u003E\u0026lt;build\u0026gt;\n        #jar名字\n        \u0026lt;finalName\u0026gt;HServer\u0026lt;/finalName\u0026gt;\n        \u0026lt;plugins\u0026gt;\n            \u0026lt;plugin\u0026gt;\n                \u0026lt;groupId\u0026gt;org.apache.maven.plugins\u0026lt;/groupId\u0026gt;\n                \u0026lt;artifactId\u0026gt;maven-compiler-plugin\u0026lt;/artifactId\u0026gt;\n                \u0026lt;version\u0026gt;3.1\u0026lt;/version\u0026gt;\n                \u0026lt;configuration\u0026gt;\n                    \u0026lt;source\u0026gt;1.8\u0026lt;/source\u0026gt;\n                    \u0026lt;target\u0026gt;1.8\u0026lt;/target\u0026gt;\n                    \u0026lt;encoding\u0026gt;UTF-8\u0026lt;/encoding\u0026gt;\n                \u0026lt;/configuration\u0026gt;\n            \u0026lt;/plugin\u0026gt;\n\n            \u0026lt;plugin\u0026gt;\n                \u0026lt;artifactId\u0026gt;maven-assembly-plugin\u0026lt;/artifactId\u0026gt;\n                \u0026lt;configuration\u0026gt;\n                    \u0026lt;finalName\u0026gt;${project.build.finalName}\u0026lt;/finalName\u0026gt;\n                    \u0026lt;appendAssemblyId\u0026gt;false\u0026lt;/appendAssemblyId\u0026gt;\n                    \u0026lt;archive\u0026gt;\n                        \u0026lt;manifest\u0026gt;\n                            #主函数的包路径\n                            \u0026lt;mainClass\u0026gt;top.test.WebApp\u0026lt;/mainClass\u0026gt;\n                        \u0026lt;/manifest\u0026gt;\n                    \u0026lt;/archive\u0026gt;\n                    \u0026lt;descriptorRefs\u0026gt;\n                        \u0026lt;descriptorRef\u0026gt;jar-with-dependencies\u0026lt;/descriptorRef\u0026gt;\n                    \u0026lt;/descriptorRefs\u0026gt;\n                \u0026lt;/configuration\u0026gt;\n                \u0026lt;executions\u0026gt;\n                    \u0026lt;execution\u0026gt;\n                        \u0026lt;id\u0026gt;make-assembly\u0026lt;/id\u0026gt;\n                        \u0026lt;phase\u0026gt;package\u0026lt;/phase\u0026gt;\n                        \u0026lt;goals\u0026gt;\n                            \u0026lt;goal\u0026gt;single\u0026lt;/goal\u0026gt;\n                        \u0026lt;/goals\u0026gt;\n                    \u0026lt;/execution\u0026gt;\n                \u0026lt;/executions\u0026gt;\n            \u0026lt;/plugin\u0026gt;\n        \u0026lt;/plugins\u0026gt;\n\u0026lt;/build\u0026gt;\n\u003C/code\u003E\u003C/pre\u003E\n\u003Ch3\u003E\n\u003Ca id=\"静态资源路径\" class=\"anchor\" href=\"#%E9%9D%99%E6%80%81%E8%B5%84%E6%BA%90%E8%B7%AF%E5%BE%84\"\u003E\u003C/a\u003E静态资源路径\u003C/h3\u003E\n\u003Cpre\u003E\u003Ccode\u003Eresources/static\n\u003C/code\u003E\u003C/pre\u003E\n\u003Ch3\u003E\n\u003Ca id=\"模板路径\" class=\"anchor\" href=\"#%E6%A8%A1%E6%9D%BF%E8%B7%AF%E5%BE%84\"\u003E\u003C/a\u003E模板路径\u003C/h3\u003E\n\u003Cpre\u003E\u003Ccode\u003Eresources/template\n\u003C/code\u003E\u003C/pre\u003E\n\u003Ch3\u003E\n\u003Ca id=\"查看相关实例代码\" class=\"anchor\" href=\"#%E6%9F%A5%E7%9C%8B%E7%9B%B8%E5%85%B3%E5%AE%9E%E4%BE%8B%E4%BB%A3%E7%A0%81\"\u003E\u003C/a\u003E查看相关实例代码\u003C/h3\u003E\n\u003Cpre\u003E\u003Ccode\u003E找到Maven的依赖包，在cn.hserver.test.目录下是大量的测试案例和代码可以查询学习和使用。\n\u003C/code\u003E\u003C/pre\u003E"},{"id":"00000000000014，ApiDoc生成功能","pId":0,"name":"14，ApiDoc生成功能","parent":null,"order":14,"sort_id":1985162,"extname":".md","isParent":false,"isHidden":false,"content":"\u003Cp\u003E\u003Cem\u003E关于这个api文档生成目前只是一个简洁版，在未来日子里相信会变得更好\u003C/em\u003E\u003C/p\u003E\n\u003Ch3\u003E\n\u003Ca id=\"第一步\" class=\"anchor\" href=\"#%E7%AC%AC%E4%B8%80%E6%AD%A5\"\u003E\u003C/a\u003E第一步\u003C/h3\u003E\n\u003Cpre\u003E\u003Ccode\u003E@Controller(value = \"/v1/Api2\", name = \"Api接口2\")\nclass ApiController{}\nvalue值会自动补全类中方法的URL，name值，在文档中有名字定义的作用，如果这个名字不定义，那么会采用控制器的全路径。\n\u003C/code\u003E\u003C/pre\u003E\n\u003Ch3\u003E\n\u003Ca id=\"第二步\" class=\"anchor\" href=\"#%E7%AC%AC%E4%BA%8C%E6%AD%A5\"\u003E\u003C/a\u003E第二步\u003C/h3\u003E\n\u003Cpre\u003E\u003Ccode\u003E在需要生成注解的方法上，添加这个注解，这个注解类似swagger的注解。\n\n  @GET(\"/get\")\n  @ApiImplicitParams(\n    value = {\n      @ApiImplicitParam(name = \"name\", value = \"名字\", required = true, dataType = DataType.String),\n      @ApiImplicitParam(name = \"sex\", value = \"性别\", required = true, dataType = DataType.Integer),\n      @ApiImplicitParam(name = \"age\", value = \"年龄\", required = true, dataType = DataType.Integer),\n    },\n    note = \"这是一个Api的Get方法\",\n    name = \"阿皮获取GET\"\n  )\n  public JsonResult get(User user) {\n    return JsonResult.ok().put(\"data\", user);\n  }\n\u003C/code\u003E\u003C/pre\u003E\n\u003Ch3\u003E\n\u003Ca id=\"第三步\" class=\"anchor\" href=\"#%E7%AC%AC%E4%B8%89%E6%AD%A5\"\u003E\u003C/a\u003E第三步\u003C/h3\u003E\n\u003Cpre\u003E\u003Ccode\u003EHServer提供了一个叫ApiDoc的类，是可以对他进行实例化，就可以获取到生成的文档的对象，你可以进行自己的文档生成定制，或者使用HServer提供            \n\n的简洁版本的文档模板。下面就是例子，ApiDoc的构造器可以传入class类型，或者传入String类型，主要目的是进行扫包，可以直接传入包名，或者传入class，然后获取包名\n  \n  //官方模板输出\n  @GET(\"/api\")\n  public void getApiData(HttpResponse httpResponse) {\n    //ApiDoc apiDoc = new ApiDoc(\"top.test\");\n    ApiDoc apiDoc = new ApiDoc(TestWebApp.class);\n    try {\n      List\u0026lt;ApiResult\u0026gt; apiData = apiDoc.getApiData();\n      HashMap\u0026lt;String,Object\u0026gt; stringObjectHashMap=new HashMap\u0026lt;\u0026gt;();\n      stringObjectHashMap.put(\"data\",apiData);\n      httpResponse.sendTemplate(\"hserver_doc.ftl\",stringObjectHashMap);\n    }catch (Exception e){\n      httpResponse.sendJson(JsonResult.error());\n    }\n  }\n  //输出json,或者自己自定名字  \n  @GET(\"/apiJson\")\n  public JsonResult getApiDataa() {\n    ApiDoc apiDoc = new ApiDoc(\"top.test\");\n    try {\n      List\u0026lt;ApiResult\u0026gt; apiData = apiDoc.getApiData();\n      return JsonResult.ok().put(\"data\",apiData);\n    }catch (Exception e){\n      return JsonResult.error();\n    }\n  }\n\u003C/code\u003E\u003C/pre\u003E"},{"id":"00000000000015，EventBus(内部的消息订阅与发布)","pId":0,"name":"15，EventBus(内部的消息订阅与发布)","parent":null,"order":15,"sort_id":2035947,"extname":".md","isParent":false,"isHidden":false,"content":"\u003Cpre\u003E\u003Ccode\u003E//有时候需要这样的一个简单功能，又不想导包，那就用这个盘他吧！\n//定义消费者\n@EventHandler(\"/aa/aa\")\npublic class EventTest{\n\n    @Event(\"aa\")\n    public void aa(Map params) {\n        try {\n            System.out.println(Thread.currentThread().getName());\n            Thread.sleep(1000);\n        } catch (InterruptedException e) {\n            e.printStackTrace();\n        }\n    }\n\n    @Event(\"bb\")\n    public void bb(Map params) {\n        try {\n            System.out.println(Thread.currentThread().getName());\n            Thread.sleep(1000);\n        } catch (InterruptedException e) {\n            e.printStackTrace();\n        }\n    }\n}\n   //定义生产者\n    @GET(\"/event\")\n    public JsonResult event(){\n        Map params = new HashMap();\n        params.put(\"a\", \"aaaaaaaaaa\");\n        params.put(\"b\", 1234);\n        params.put(\"c\", 0);\n        params.put(\"d\", true);\n        HServerEvent.sendEvent(\"/aa/aa/aa\", params);\n        return JsonResult.ok();\n    }\n    \n    @GET(\"/queueSize\")\n    public JsonResult getQueueSize(){\n        int size = HServerEvent.queueSize();\n        return JsonResult.ok().put(\"size\",size);\n    }\n\n注意：队列不易过大，过大会导致内存急剧上升，当然几十万没得问题，还需要过大的话，请调整jvm启动参数,队列最大值是int的最大值，Integer.MAX_VALUE\n     反正几十万，几万的，没啥问题，放心用       \n\u003C/code\u003E\u003C/pre\u003E"},{"id":"00000000000016，Track跟踪","pId":0,"name":"16，Track跟踪","parent":null,"order":16,"sort_id":2126027,"extname":".md","isParent":false,"isHidden":false,"content":"\u003Cpre\u003E\u003Ccode\u003E使用动态字节码技术，在初始化对需要跟踪的方法进行，字节码处理，\n使用方法：\n        1.在任意方法上添加，@Track 注解:例如\n          @Track\n          @GET(\"/track\")\n          public JsonResult track() {\n            return JsonResult.ok();\n          }\n\n\n    ​            \n2.实现TrackAdapter接口，并在类上用 @Bean标识\n    @Bean\n    @Slf4j\n    public class TrackImpl implements TrackAdapter {\n        @Override\n        public void track(Class clazz, Method method,StackTraceElement[] stackTraceElements, long start, long end) throws Exception {\n            log.info(\"当前类：{},当前方法：{},耗时：{}\", clazz.getName(), stackTraceElements[1].getMethodName(), (end - start) + \"ms\");\n        }\n    }\n\u003C/code\u003E\u003C/pre\u003E"},{"id":"00000000000017，单元测试","pId":0,"name":"17，单元测试","parent":null,"order":17,"sort_id":2132417,"extname":".md","isParent":false,"isHidden":false,"content":"\u003Cpre\u003E\u003Ccode\u003E    @RunWith(HServerTest.class)\n    //指定一个外部的类，他会更具这个类递归扫描子类，并放入容器\n    //@HServerBootTest(TestWebApp.class)\n    public class test {\n    \n        @Autowired\n        private User user;\n    \n        @Test\n        public void main(){\n            System.out.println(user.getName());;\n        }\n    }\n\u003C/code\u003E\u003C/pre\u003E"},{"id":"00000000000018，SSL配置","pId":0,"name":"18，SSL配置","parent":null,"order":18,"sort_id":2185393,"extname":".md","isParent":false,"isHidden":false,"content":"\u003Cpre\u003E\u003Ccode\u003E  在application.properties配置文件添加\n  \n  #举栗子：nginx版本的证书下载可能会得到 (xxx.pem或者xxx.cert) xxx.key\n  #注意下载的证书中 key文件需要转换成 pk8 文件\n  #因为netty4不支持pkcs12格式的私钥, 所以需要将私钥转换成pkcs8格式.\n  #openssl pkcs8 -in my.key -topk8 -out my.pk8\n  #转换过程需要你设置一个密码.\n  \n  方案一：\n  #jar路径，证书文件应该放在\\src\\main\\resources\\ssl\\ 目录里，打包会一起打包\n  certPath=hserver.pem\n  privateKeyPath=hserver.pk8\n  privateKeyPwd=123\n  \n  方案二：\n  #外置路径，指定一个绝对路径即可\n  certPath=/home/ssl/hserver.pem\n  privateKeyPath=/home/ssl/hserver.pk8\n  privateKeyPwd=123\n\n  然后监听443端口，你就能https 访问了。\n\u003C/code\u003E\u003C/pre\u003E"},{"id":"00000000000019，自定义方法级别注解","pId":0,"name":"19，自定义方法级别注解","parent":null,"order":19,"sort_id":2185394,"extname":".md","isParent":false,"isHidden":false,"content":"\u003Cpre\u003E\u003Ccode\u003E  //创建一个@Log 注解，该注解必须继承@Auto注解。例如下面.\n  \n  @Target(ElementType.METHOD)\n  @Retention(RetentionPolicy.RUNTIME)\n  @Documented\n  @Auto\n  public @interface Log {\n  }\n\n  \n  //自己实现AnnotationAdapter接口同时使用@Bean标注 .例如\n  @Bean\n  public class MyAutoAnnotationAdapter implements AnnotationAdapter {\n  \n    @Override\n    public void before(Annotation annotation, Object[] args, Class clazz, Method method) {\n  \n      System.out.println(annotation);\n      System.out.println(args.length);\n      if (args.length \u0026gt; 0) {\n        System.out.println(args[0]);\n      }\n      System.out.println(clazz);\n    }\n    \n    @Override\n    public void after(Annotation annotation, Object object, Class clazz, Method method) {\n      System.out.println(object);\n    }\n  }\n\n  \n  //然后你就能这个自己实现的接口中获取到.进行前置后置的处理.\n  //通过参数Annotation 来判断是哪一个注解然后进行相关逻辑处理.\n\u003C/code\u003E\u003C/pre\u003E"},{"id":"00000000000020，自定义Banner","pId":0,"name":"20，自定义Banner","parent":null,"order":20,"sort_id":2342458,"extname":".md","isParent":false,"isHidden":false,"content":"\u003Cp\u003Eresources文件夹里存放一个banner.txt 里面放入你图标就可以了.\u003C/p\u003E"}],"content":{"1963855":"\u003Ch5\u003E\n\u003Ca id=\"为了让开发者快速理解和使用hserver将大部分的注解定义的名字和spring相似这样让开发者可以快熟理解和使用\" class=\"anchor\" href=\"#%E4%B8%BA%E4%BA%86%E8%AE%A9%E5%BC%80%E5%8F%91%E8%80%85%E5%BF%AB%E9%80%9F%E7%90%86%E8%A7%A3%E5%92%8C%E4%BD%BF%E7%94%A8hserver%E5%B0%86%E5%A4%A7%E9%83%A8%E5%88%86%E7%9A%84%E6%B3%A8%E8%A7%A3%E5%AE%9A%E4%B9%89%E7%9A%84%E5%90%8D%E5%AD%97%E5%92%8Cspring%E7%9B%B8%E4%BC%BC%E8%BF%99%E6%A0%B7%E8%AE%A9%E5%BC%80%E5%8F%91%E8%80%85%E5%8F%AF%E4%BB%A5%E5%BF%AB%E7%86%9F%E7%90%86%E8%A7%A3%E5%92%8C%E4%BD%BF%E7%94%A8\"\u003E\u003C/a\u003E为了让开发者快速理解和使用HServer，将大部分的注解定义的名字和Spring相似，这样让开发者可以快熟理解和使用.\u003C/h5\u003E\n\u003Cpre\u003E\u003Ccode\u003E@Bean\n将Bean对象加入IOC容器中比如\n    //默认按类型加入IOC容器\n    @Bean\n    class TestService{}\n    //指定名字加入容器，装配的时候就只能通过名字装配了\n    @Bean(\"testService1\")\n    class Test{}\n    \n    \n@Autowired\n自动装配注解\n    //按类型注入\n    @Autowired\n    private TestService testService;\n    //按Bean名字注入\n    @Autowired(\"testServer1\")\n    private TestService testService; \n    \n       \n@Controller\n控制器注解，将控制器加入IOC容器中，类似Spring mvc\n注解在类上面直接加上即可比如\n    //Index控制器\n    @Controller\n    class IndexController{}\n    //value 会自动补全类中的url定义的URL，name值在鉴权中和APi文档生成时可以提取当前模块名\n    //如果不写name值，name将会自动使用包名代替\n    @Controller(value = \"/v1/Api2\", name = \"Api接口2\")\n    class IndexController{}\n       \n@GET,@POST,@RequestMapping\n方法注解，在@Controller注解类类中使用，标注一个方法为GET或者POST方法，例如\n    @GET(\"/index\")\n    public void index(){}  \n    @POST(\"/index\")\n    public void index(){}\n    \n    //url规则匹配\n    @GET(\"/url1/{url}\")\n    public String url(HttpRequest httpRequest){\n        String url = httpRequest.query(\"url\");\n        System.out.println(url);\n        return url;\n    }\n\n    @GET(\"/url/{url}\")\n    public String url(String url){\n        return \"匹配到的URL:\"+url;\n    }\n\n    @POST(\"/a/{url}/bb\")\n    public String ab(String url){\n        return \"匹配到的URL:\"+url;\n    } \n     \n    //2.9.4+以上支持\n    @RequestMapping(value = \"/PUT\", method = RequestMethod.PUT)\n    public JsonResult PUT() {\n      return JsonResult.ok();\n    }\n    //2.9.4+以上支持\n    @RequestMapping(value = \"/get_post\", method = {RequestMethod.POST,RequestMethod.GET})\n    public JsonResult get_post() {\n      return JsonResult.ok();\n    }\n    \n    //2.9.4+以上支持\n    //全类型\n    @RequestMapping(value = \"/all\")\n    public JsonResult all() {\n      return JsonResult.ok();\n    }\n\n    \n@Filter\n拦截器注解，标注一个类为拦截器，和JavaEE的Filter类似\n    @Filter(1)//1表示拦截优先级，越小越优先\n    public class MyFilter1 implements FilterAdapter {}\n    //需要实现FilterAdapter接口\n    \n    \n@Hook\nhook注解就是Aop\n    @Hook(value = Test.class, method = \"show\")\n    public class HookTest implements HookAdapter {}\n    //value表示aop的类,method要hook的方法，必须实现HookAdapter\n    \n    \n@Task\n 定时任务\n    @Task(name = \"测试定时任务Cron\", time =\"*/5 * * * * ?\")\n    //标记在方法上，同时该类需要被@Bean 标记\n    @Task(name = \"测试定时任务1\", time =\"2000\")\n    public void timerTask() {}\n    \n    \n@WebSocket\n实现websocket通信\n    @WebSocket(\"/ws\")\n    public class WebSocketTest implements WebSocketHandler {}\n    //这样就可以完成基本的通信了\n    \n    \n@Configuration\n自定配置注解，需要配合@Bean注解一起使用，最后会把方法里面的返回的对象\n存储到IOC容器中，同时可以通过Autowired注解注入\n    @Configuration\n    public class DataConfig {\n    \n        //自定义名字（用例：比如多数据源注入）\n        @Bean(\"createUser\")\n        public User createUser(){\n            User user = new User();\n            user.setAge(999);\n            user.setName(\"我是配置类自定义名字的数据\");\n            user.setSex(\"未知\");\n            return user;\n        }\n    \n       //按类型存储 \n        @Bean\n        public User createUser1(){\n            User user = new User();\n            user.setAge(999);\n            user.setName(\"我是配置类的默认数据\");\n            user.setSex(\"未知\");\n            return user;\n        }\n    \n    }\n    \n    \n@RpcService\n标注一个Bean对象是一个rpc服务,也可以分配一个名字\n    @Bean\n    @RpcService\n    public class RpcServiceTest {\n        public String test(String name){\n            return name+\"我是RPC\";\n        }\n    }  \n    \n    \n@Resource\n注入一个Rpc服务，也可以通过名字注入。详情，请看文档介绍   \n    @Resource\n    private RpcServiceTest rpcServiceTest;\n    \n    \n@Sign(\"MD5\")\n@RequiresRoles(\"角色\")\n@RequiresPermissions(value = {\"/权限1\",\"/权限2\"}, logical=Logical.OR)\n该注解用于标注控制器里面的方法，方便自己实现sign签名算法，\n角色检查，权限检查，实现token等，详情下面的对应接口。\n\n\n@BeetlSQL\n该注解实现对Beetlsql的getMpper方法做了一个封装，\n你只需要在mapper中加入该注解，然后进行装配到Service就可以了，\n详情可以参考官方放在的例子\n\u003C/code\u003E\u003C/pre\u003E","1963857":"\u003Cp\u003E#第一步pom依赖引入\u003C/p\u003E\n\u003Cpre\u003E\u003Ccode\u003E\u0026lt;dependency\u0026gt;\n    \u0026lt;groupId\u0026gt;cn.hserver\u0026lt;/groupId\u0026gt;\n    \u0026lt;artifactId\u0026gt;HServer\u0026lt;/artifactId\u0026gt;\n    \u0026lt;version\u0026gt;最新版\u0026lt;/version\u0026gt;\n\u0026lt;/dependency\u0026gt;\n\npublic class WebApp {\n    public static void main(String[] args) {\n        //运行官方例子,直接运行既可以了，默认自带了一些例子。\n        HServerApplication.run(TestWebApp.class, 8888);\n    }\n}\n\n\n#第二步搞一个主函数\npublic class WebApp {\n    public static void main(String[] args) {\n        HServerApplication.run(WebApp.class, 8888);\n    }\n}\n\n#第三步同主函数建立一个包文件夹比如controller\n\n@Controller\npublic class Hello {\n\n    @GET(\"/hello\")\n    public Map index(HttpRequest request, String name) {\n        Map\u0026lt;String, Object\u0026gt; res = new HashMap\u0026lt;\u0026gt;();\n        res.put(\"code\", 200);\n        res.put(\"res\", request.getRequestParams());\n        res.put(\"msg\", \"Hello\");\n        return res;\n    }\n    \n    /**\n     * 模板测试\n     * @param httpResponse\n     */\n    @GET(\"/template\")\n    public void template(HttpResponse httpResponse) {\n        User user = new User();\n        user.setAge(20);\n        user.setName(\"xx\");\n        user.setSex(\"男\");\n        Map\u0026lt;String,Object\u0026gt; obj=new HashMap\u0026lt;\u0026gt;();\n        obj.put(\"user\",user);\n//        httpResponse.sendTemplate(\"/admin/user/list.ftl\", obj);\n        httpResponse.sendTemplate(\"a.ftl\", obj);\n    }\n}\n#就这样你就完成了一个简单得get请求定义，更多例子，可以参考包top.test下面的例子\n\u003C/code\u003E\u003C/pre\u003E","1963858":"\u003Cpre\u003E\u003Ccode\u003E    #File类型得\n    @GET(\"/downFile\")\n    public void downFile(HttpRequest request, HttpResponse response) {\n      response.setDownloadFile(new File(\"D:\\\\Java\\\\HServer\\\\README.md\"));\n    }\n\n    #InputStream 类型得\n    @GET(\"/downInputStream\")\n    public void downInputStream(HttpRequest request, HttpResponse response) throws Exception {\n      File file = new File(\"D:\\\\Java\\\\HServer\\\\README.md\");\n      InputStream fileInputStream = new FileInputStream(file);\n      response.setDownloadFile(fileInputStream,\"README.md\");\n    }\n\n    @POST(\"/file\")\n    public Map file(HttpRequest request) {\n        //单个文件\n          FileItem file = request.queryFile(\"file\");\n          //多个文件上传\n          Map\u0026lt;String, FileItem\u0026gt; fileItems = request.getFileItems();\n      //然后对FileItem 进行保存，就可以了\n      }\n\u003C/code\u003E\u003C/pre\u003E","1963860":"\u003Cp\u003E#必须实现HookAdapter的接口\u003C/p\u003E\n\u003Cpre\u003E\u003Ccode\u003E#同时被@Hook注解标注\n\n@Slf4j\n\n@Hook(value = Test.class, method = \"show\")\n\npublic class HookTest implements HookAdapter {\n\n\n\n    @Override\n\n    public void before(Object[] objects) {\n\n        log.info(\"aop.-前置拦截：\" + objects[0]);\n\n        objects[0]=\"666\";\n\n    }\n\n\n\n    @Override\n\n    public Object after(Object object) {\n\n        return object + \"aop-后置拦截\";\n\n    }\n\n}\n\u003C/code\u003E\u003C/pre\u003E","1963864":"\u003Cp\u003E#必须实现FilterAdapter接口，同时被@Filter标注，数字越小，优先级越高，切不要重复\u003C/p\u003E\n\u003Cpre\u003E\u003Ccode\u003E@Slf4j\n\n@Filter(1)\n\npublic class MyFilter2 implements FilterAdapter {\n\n    @Override\n\n    public void doFilter(FilterChain chain, Webkit webkit) {\n\n        log.info(\"MyFilter-\u0026gt;1\");\n\n        chain.doFilter(webkit);\n\n    }\n\n}\n\u003C/code\u003E\u003C/pre\u003E","1963867":"\u003Cpre\u003E\u003Ccode\u003E#需要被@Bean注解标注,可以通过TaskManager类进行定时任务的控制，动态添加和删除\n@Bean\npublic class TaskTest {\n    \n    @Autowired\n    private TestService testService;\n\n    private boolean flag = true;\n\n    public void dynamicAddTimer() {\n        System.out.println(\"动态添加定时任务\");\n        TaskManager.addTask(\"测试任务2\", \"2000\", TestTask.class,\"666\");\n    }\n    \n    \n    @Task(name = \"测试定时任务1\", time =\"*/5 * * * * ?\")\n    public void timerTask() {\n        System.out.println(\"测试定时任务，注入的对象调用结果:\" + testService.testa());\n        if (flag) {\n            dynamicAddTimer();\n            flag = false;\n        }\n    }\n\n    @Task(name = \"测试定时任务2\", time = \"2000\")\n    public void removeTask() {\n        //干掉方法注解版本\n        boolean task1 = TaskManager.removeTask(\"测试定时任务1\");\n        //干掉动态添加的\n        boolean task2 = TaskManager.removeTask(\"测试任务2\");\n        //干掉自己\n        boolean task3 = TaskManager.removeTask(\"测试定时任务2\");\n        //结果\n        System.out.println(\"任务已经被干掉了 tash1=\" + task1 + \",task2=\" + task2 + \",task3=\" + task3);\n    }\n\n}\n\n//动态添加定时任务的实现类必须要实现一个TaskJob,样才能被TaskManager管理\n//添加任务 TaskManager.addTask(\"测试任务2\", \"2000\", TestTask.class,\"666\");\n//删除任务  boolean is_success = TaskManager.removeTask(\"测试任务2\");\npublic class TestTask implements TaskJob {\n\n    @Override\n    public void exec(Object... args) {\n        String args_ = \"\";\n        for (Object arg : args) {\n            args_ += arg.toString();\n        }\n        System.out.println(\"测试定时器动态添加任务，参数是：\" + args_);\n    }\n}\n\u003C/code\u003E\u003C/pre\u003E","1963889":"\u003Cpre\u003E\u003Ccode\u003E#需要被@WebSocket标注同时给一个连接地址，最后实现WebSocketHandler接口，\n#Ws类定义了简单的发送方法，如果有其他的业务操作，可以获取ChannelHandlerContext，进行操作\n\n@WebSocket(\"/ws\")\npublic class WebSocketTest implements WebSocketHandler {\n\n    @Autowired\n    private TestService testService;\n\n    @Override\n    public void onConnect(Ws ws) {\n        System.out.println(\"连接成功,分配的UID：\" + ws.getUid());\n    }\n\n    @Override\n    public void onMessage(Ws ws) {\n        ws.send(\"666\" + testService.testa() + ws.getUid());\n        System.out.println(\"收到的消息,\"+ws.getMessage()+\",UID：\" + ws.getUid());\n    }\n\n    @Override\n    public void disConnect(Ws ws) {\n        System.out.println(\"断开连接,UID:\" + ws.getUid());\n    }\n}\n\u003C/code\u003E\u003C/pre\u003E","1963890":"\u003Cpre\u003E\u003Ccode\u003Eapplication.properties文件配置\n    #开启访问统计\n    statistics=true\n    #统计规则:以逗号分割的正则表达式\n    statisticalRules=/hel.*,/admin/.*\n#StatisticsHandler操作\n    #获取所有的IP地址\n    StatisticsHandler.getIpMap()\n    #请求队列（调用的URI，(发送大小，接收大小)宽带监视，耗时时间）\n    StatisticsHandler.getLogRequestQue()\n    #唯一IP请求的数量 uv\n    StatisticsHandler.getUniqueIpCount()\n    #请求总数   pv\n    StatisticsHandler.getCount()\n    #uri记录 被访问的记录（）\n    StatisticsHandler.getUriData()\n#提示：\n1，如果自己要做统计，完全可以自定义一个定时器，动态保存数据哦\n2，StatisticsHandler,提供了一个remove方法,remove，用来清除，或者保存数据用，它会返回一个最新的数据同时清除自己\n3，如果开启统计，请务必，执行Remove方法，不然，内存可能就会蹦\n\u003C/code\u003E\u003C/pre\u003E","1963891":"\u003Cpre\u003E\u003Ccode\u003E类必须要被@Bean注解，同时实现GlobalException接口，\n一个项目中最多只有一个GlobalException实现哦，可以没有.没有异常处理，同时又报错了，那么直接显示错误\n@Bean\npublic class WebException implements GlobalException {\n\n    @Override\n    public void handler(Exception exception, Webkit webkit) {\n        exception.printStackTrace();\n        System.out.println(webkit.httpRequest.getUri() + \"---\u0026gt;\" + exception.getMessage());\n        webkit.httpResponse.sendHtml(\"全局异常处理\");\n    }\n}\n\u003C/code\u003E\u003C/pre\u003E","1963892":"\u003Cpre\u003E\u003Ccode\u003E 类必须要被@Bean注解，同时实现InitRunner接口，\n @Bean\n public class RunInit implements InitRunner {\n \n     @Autowired\n     private User user;\n \n     @Override\n     public void init(String[] args) {\n         System.out.println(\"初始化方法：注入的User对象的名字是--\u0026gt;\"+user.getName());\n     }\n }\n\u003C/code\u003E\u003C/pre\u003E","1963893":"\u003Cpre\u003E\u003Ccode\u003E//请使用相关注解对控制器的方法做标记，这样在执行到被注解标记的方法就会执行下面的相关方法\n//  List\u0026lt;RouterPermission\u0026gt; routerPermissions = PermissionAdapter.getRouterPermissions();\n// 通过上面的代码可以获取到所有标记的注解，他可以干嘛？\n// 同步后台数据库里面的权限，后台管理面里面可以动态给角色分配权限。\n// 自己做一个下拉选择列表，创建角色分配权限时，多选即可。\n\n/**\n * 验证逻辑请自己实现哦\n */\n@Bean\npublic class TestPermission implements PermissionAdapter {\n\n    @Override\n    public void requiresPermissions(RequiresPermissions requiresPermissions, Webkit webkit) {\n        //这里你可以实现一套自己的权限检查算法逻辑，判断，\n        //如果满足权限，不用其他操作，如果不满足权限，那么你可以通过，Webkit里面的方法直接输出相关内容\n        //或者自定义一个异常类，在全局异常类做相关操作\n        System.out.println(requiresPermissions.value()[0]);\n    }\n\n    @Override\n    public void requiresRoles(RequiresRoles requiresRoles, Webkit webkit) {\n        //这里你可以实现一套自己的角色检查算法逻辑，判断，\n        //其他逻辑同上\n        System.out.println(requiresRoles.value()[0]);\n    }\n\n    @Override\n    public void sign(Sign sign, Webkit webkit) {\n       //这里你可以实现一套自己的接口签名算法检查算法逻辑，判断，\n       //其他逻辑同上\n       Map\u0026lt;String, String\u0026gt; requestParams = webkit.httpRequest.getRequestParams();\n       String sign1 = webkit.httpRequest.getHeader(\"sign\");\n       System.out.println(sign.value());\n    }\n}\n\u003C/code\u003E\u003C/pre\u003E","1963895":"\u003Cp\u003E依赖版本要大于等于2.5版本\n要有主节点\n要有从节点\n主从节点共用接口层\n源码例子（请看gitees的rpc项目）\n举栗子\u003C/p\u003E\n\u003Cp\u003E1.主节点\u003C/p\u003E\n\u003Cpre\u003E\u003Ccode\u003E    #-----------------集群-------------\n    #是否开启集群模式\n    app.cloud.open=true\n    #集群名字\n    app.cloud.name=ServerA\n    #是否是主机\n    app.cloud.master.open=true\n\n    @Resource\n    private RpcService rpcService;\n    @Resource(\"rpc\")\n    private RpcService rpcService;\n\u003C/code\u003E\u003C/pre\u003E\n\u003Cp\u003E2.从节点\u003C/p\u003E\n\u003Cpre\u003E\u003Ccode\u003E    #-----------------集群-------------\n    #是否开启集群模式\n    app.cloud.open=true\n    #集群名字\n    app.cloud.name=ServerB\n    #是否是从机\n    app.cloud.slave.open=true\n    #从机连接主机的IP地址\n    app.cloud.slave.master.host=127.0.0.1\n\n    @Bean\n    @RpcService\n    public class RpcServiceImp implements RpcService{\n        public String test(String name){\n            return name+\"我是RPC\";\n        }\n    }\n\n    @Bean\n    @RpcService(\"rpc\")\n    public class RpcServiceImp implements RpcService{\n        public String test(String name){\n            return name+\"我是RPC\";\n        }\n    }\n\u003C/code\u003E\u003C/pre\u003E\n\u003Cp\u003E可以多从机注册到同一个主机上，调用轮训负载均衡调用。启动主机，在启动从机，从机自动连接主机断开也会自动重新连接\u003C/p\u003E","1963904":"\u003Ch3\u003E\n\u003Ca id=\"在controller层中定义的方法\" class=\"anchor\" href=\"#%E5%9C%A8controller%E5%B1%82%E4%B8%AD%E5%AE%9A%E4%B9%89%E7%9A%84%E6%96%B9%E6%B3%95\"\u003E\u003C/a\u003E在Controller层中定义的方法\u003C/h3\u003E\n\u003Cp\u003E参数可以是基础数据类型或者bean对象，或者HttpRequest，HttpResponse，（需要是这个包下面的cn.hserver.core.interfaces.的对象）当不是表单提交时，可以通过httpRequest.getRawData()，获取到请求的数据。\u003C/p\u003E\n\u003Ch3\u003E\n\u003Ca id=\"打包jar\" class=\"anchor\" href=\"#%E6%89%93%E5%8C%85jar\"\u003E\u003C/a\u003E打包jar，\u003C/h3\u003E\n\u003Cp\u003E只需要在pom.xml 添加打包命令即可\u003C/p\u003E\n\u003Cpre\u003E\u003Ccode\u003E\u0026lt;build\u0026gt;\n        #jar名字\n        \u0026lt;finalName\u0026gt;HServer\u0026lt;/finalName\u0026gt;\n        \u0026lt;plugins\u0026gt;\n            \u0026lt;plugin\u0026gt;\n                \u0026lt;groupId\u0026gt;org.apache.maven.plugins\u0026lt;/groupId\u0026gt;\n                \u0026lt;artifactId\u0026gt;maven-compiler-plugin\u0026lt;/artifactId\u0026gt;\n                \u0026lt;version\u0026gt;3.1\u0026lt;/version\u0026gt;\n                \u0026lt;configuration\u0026gt;\n                    \u0026lt;source\u0026gt;1.8\u0026lt;/source\u0026gt;\n                    \u0026lt;target\u0026gt;1.8\u0026lt;/target\u0026gt;\n                    \u0026lt;encoding\u0026gt;UTF-8\u0026lt;/encoding\u0026gt;\n                \u0026lt;/configuration\u0026gt;\n            \u0026lt;/plugin\u0026gt;\n\n            \u0026lt;plugin\u0026gt;\n                \u0026lt;artifactId\u0026gt;maven-assembly-plugin\u0026lt;/artifactId\u0026gt;\n                \u0026lt;configuration\u0026gt;\n                    \u0026lt;finalName\u0026gt;${project.build.finalName}\u0026lt;/finalName\u0026gt;\n                    \u0026lt;appendAssemblyId\u0026gt;false\u0026lt;/appendAssemblyId\u0026gt;\n                    \u0026lt;archive\u0026gt;\n                        \u0026lt;manifest\u0026gt;\n                            #主函数的包路径\n                            \u0026lt;mainClass\u0026gt;top.test.WebApp\u0026lt;/mainClass\u0026gt;\n                        \u0026lt;/manifest\u0026gt;\n                    \u0026lt;/archive\u0026gt;\n                    \u0026lt;descriptorRefs\u0026gt;\n                        \u0026lt;descriptorRef\u0026gt;jar-with-dependencies\u0026lt;/descriptorRef\u0026gt;\n                    \u0026lt;/descriptorRefs\u0026gt;\n                \u0026lt;/configuration\u0026gt;\n                \u0026lt;executions\u0026gt;\n                    \u0026lt;execution\u0026gt;\n                        \u0026lt;id\u0026gt;make-assembly\u0026lt;/id\u0026gt;\n                        \u0026lt;phase\u0026gt;package\u0026lt;/phase\u0026gt;\n                        \u0026lt;goals\u0026gt;\n                            \u0026lt;goal\u0026gt;single\u0026lt;/goal\u0026gt;\n                        \u0026lt;/goals\u0026gt;\n                    \u0026lt;/execution\u0026gt;\n                \u0026lt;/executions\u0026gt;\n            \u0026lt;/plugin\u0026gt;\n        \u0026lt;/plugins\u0026gt;\n\u0026lt;/build\u0026gt;\n\u003C/code\u003E\u003C/pre\u003E\n\u003Ch3\u003E\n\u003Ca id=\"静态资源路径\" class=\"anchor\" href=\"#%E9%9D%99%E6%80%81%E8%B5%84%E6%BA%90%E8%B7%AF%E5%BE%84\"\u003E\u003C/a\u003E静态资源路径\u003C/h3\u003E\n\u003Cpre\u003E\u003Ccode\u003Eresources/static\n\u003C/code\u003E\u003C/pre\u003E\n\u003Ch3\u003E\n\u003Ca id=\"模板路径\" class=\"anchor\" href=\"#%E6%A8%A1%E6%9D%BF%E8%B7%AF%E5%BE%84\"\u003E\u003C/a\u003E模板路径\u003C/h3\u003E\n\u003Cpre\u003E\u003Ccode\u003Eresources/template\n\u003C/code\u003E\u003C/pre\u003E\n\u003Ch3\u003E\n\u003Ca id=\"查看相关实例代码\" class=\"anchor\" href=\"#%E6%9F%A5%E7%9C%8B%E7%9B%B8%E5%85%B3%E5%AE%9E%E4%BE%8B%E4%BB%A3%E7%A0%81\"\u003E\u003C/a\u003E查看相关实例代码\u003C/h3\u003E\n\u003Cpre\u003E\u003Ccode\u003E找到Maven的依赖包，在cn.hserver.test.目录下是大量的测试案例和代码可以查询学习和使用。\n\u003C/code\u003E\u003C/pre\u003E","1985162":"\u003Cp\u003E\u003Cem\u003E关于这个api文档生成目前只是一个简洁版，在未来日子里相信会变得更好\u003C/em\u003E\u003C/p\u003E\n\u003Ch3\u003E\n\u003Ca id=\"第一步\" class=\"anchor\" href=\"#%E7%AC%AC%E4%B8%80%E6%AD%A5\"\u003E\u003C/a\u003E第一步\u003C/h3\u003E\n\u003Cpre\u003E\u003Ccode\u003E@Controller(value = \"/v1/Api2\", name = \"Api接口2\")\nclass ApiController{}\nvalue值会自动补全类中方法的URL，name值，在文档中有名字定义的作用，如果这个名字不定义，那么会采用控制器的全路径。\n\u003C/code\u003E\u003C/pre\u003E\n\u003Ch3\u003E\n\u003Ca id=\"第二步\" class=\"anchor\" href=\"#%E7%AC%AC%E4%BA%8C%E6%AD%A5\"\u003E\u003C/a\u003E第二步\u003C/h3\u003E\n\u003Cpre\u003E\u003Ccode\u003E在需要生成注解的方法上，添加这个注解，这个注解类似swagger的注解。\n\n  @GET(\"/get\")\n  @ApiImplicitParams(\n    value = {\n      @ApiImplicitParam(name = \"name\", value = \"名字\", required = true, dataType = DataType.String),\n      @ApiImplicitParam(name = \"sex\", value = \"性别\", required = true, dataType = DataType.Integer),\n      @ApiImplicitParam(name = \"age\", value = \"年龄\", required = true, dataType = DataType.Integer),\n    },\n    note = \"这是一个Api的Get方法\",\n    name = \"阿皮获取GET\"\n  )\n  public JsonResult get(User user) {\n    return JsonResult.ok().put(\"data\", user);\n  }\n\u003C/code\u003E\u003C/pre\u003E\n\u003Ch3\u003E\n\u003Ca id=\"第三步\" class=\"anchor\" href=\"#%E7%AC%AC%E4%B8%89%E6%AD%A5\"\u003E\u003C/a\u003E第三步\u003C/h3\u003E\n\u003Cpre\u003E\u003Ccode\u003EHServer提供了一个叫ApiDoc的类，是可以对他进行实例化，就可以获取到生成的文档的对象，你可以进行自己的文档生成定制，或者使用HServer提供            \n\n的简洁版本的文档模板。下面就是例子，ApiDoc的构造器可以传入class类型，或者传入String类型，主要目的是进行扫包，可以直接传入包名，或者传入class，然后获取包名\n  \n  //官方模板输出\n  @GET(\"/api\")\n  public void getApiData(HttpResponse httpResponse) {\n    //ApiDoc apiDoc = new ApiDoc(\"top.test\");\n    ApiDoc apiDoc = new ApiDoc(TestWebApp.class);\n    try {\n      List\u0026lt;ApiResult\u0026gt; apiData = apiDoc.getApiData();\n      HashMap\u0026lt;String,Object\u0026gt; stringObjectHashMap=new HashMap\u0026lt;\u0026gt;();\n      stringObjectHashMap.put(\"data\",apiData);\n      httpResponse.sendTemplate(\"hserver_doc.ftl\",stringObjectHashMap);\n    }catch (Exception e){\n      httpResponse.sendJson(JsonResult.error());\n    }\n  }\n  //输出json,或者自己自定名字  \n  @GET(\"/apiJson\")\n  public JsonResult getApiDataa() {\n    ApiDoc apiDoc = new ApiDoc(\"top.test\");\n    try {\n      List\u0026lt;ApiResult\u0026gt; apiData = apiDoc.getApiData();\n      return JsonResult.ok().put(\"data\",apiData);\n    }catch (Exception e){\n      return JsonResult.error();\n    }\n  }\n\u003C/code\u003E\u003C/pre\u003E","2035947":"\u003Cpre\u003E\u003Ccode\u003E//有时候需要这样的一个简单功能，又不想导包，那就用这个盘他吧！\n//定义消费者\n@EventHandler(\"/aa/aa\")\npublic class EventTest{\n\n    @Event(\"aa\")\n    public void aa(Map params) {\n        try {\n            System.out.println(Thread.currentThread().getName());\n            Thread.sleep(1000);\n        } catch (InterruptedException e) {\n            e.printStackTrace();\n        }\n    }\n\n    @Event(\"bb\")\n    public void bb(Map params) {\n        try {\n            System.out.println(Thread.currentThread().getName());\n            Thread.sleep(1000);\n        } catch (InterruptedException e) {\n            e.printStackTrace();\n        }\n    }\n}\n   //定义生产者\n    @GET(\"/event\")\n    public JsonResult event(){\n        Map params = new HashMap();\n        params.put(\"a\", \"aaaaaaaaaa\");\n        params.put(\"b\", 1234);\n        params.put(\"c\", 0);\n        params.put(\"d\", true);\n        HServerEvent.sendEvent(\"/aa/aa/aa\", params);\n        return JsonResult.ok();\n    }\n    \n    @GET(\"/queueSize\")\n    public JsonResult getQueueSize(){\n        int size = HServerEvent.queueSize();\n        return JsonResult.ok().put(\"size\",size);\n    }\n\n注意：队列不易过大，过大会导致内存急剧上升，当然几十万没得问题，还需要过大的话，请调整jvm启动参数,队列最大值是int的最大值，Integer.MAX_VALUE\n     反正几十万，几万的，没啥问题，放心用       \n\u003C/code\u003E\u003C/pre\u003E","2126027":"\u003Cpre\u003E\u003Ccode\u003E使用动态字节码技术，在初始化对需要跟踪的方法进行，字节码处理，\n使用方法：\n        1.在任意方法上添加，@Track 注解:例如\n          @Track\n          @GET(\"/track\")\n          public JsonResult track() {\n            return JsonResult.ok();\n          }\n\n\n    ​            \n2.实现TrackAdapter接口，并在类上用 @Bean标识\n    @Bean\n    @Slf4j\n    public class TrackImpl implements TrackAdapter {\n        @Override\n        public void track(Class clazz, Method method,StackTraceElement[] stackTraceElements, long start, long end) throws Exception {\n            log.info(\"当前类：{},当前方法：{},耗时：{}\", clazz.getName(), stackTraceElements[1].getMethodName(), (end - start) + \"ms\");\n        }\n    }\n\u003C/code\u003E\u003C/pre\u003E","2132417":"\u003Cpre\u003E\u003Ccode\u003E    @RunWith(HServerTest.class)\n    //指定一个外部的类，他会更具这个类递归扫描子类，并放入容器\n    //@HServerBootTest(TestWebApp.class)\n    public class test {\n    \n        @Autowired\n        private User user;\n    \n        @Test\n        public void main(){\n            System.out.println(user.getName());;\n        }\n    }\n\u003C/code\u003E\u003C/pre\u003E","2185393":"\u003Cpre\u003E\u003Ccode\u003E  在application.properties配置文件添加\n  \n  #举栗子：nginx版本的证书下载可能会得到 (xxx.pem或者xxx.cert) xxx.key\n  #注意下载的证书中 key文件需要转换成 pk8 文件\n  #因为netty4不支持pkcs12格式的私钥, 所以需要将私钥转换成pkcs8格式.\n  #openssl pkcs8 -in my.key -topk8 -out my.pk8\n  #转换过程需要你设置一个密码.\n  \n  方案一：\n  #jar路径，证书文件应该放在\\src\\main\\resources\\ssl\\ 目录里，打包会一起打包\n  certPath=hserver.pem\n  privateKeyPath=hserver.pk8\n  privateKeyPwd=123\n  \n  方案二：\n  #外置路径，指定一个绝对路径即可\n  certPath=/home/ssl/hserver.pem\n  privateKeyPath=/home/ssl/hserver.pk8\n  privateKeyPwd=123\n\n  然后监听443端口，你就能https 访问了。\n\u003C/code\u003E\u003C/pre\u003E","2185394":"\u003Cpre\u003E\u003Ccode\u003E  //创建一个@Log 注解，该注解必须继承@Auto注解。例如下面.\n  \n  @Target(ElementType.METHOD)\n  @Retention(RetentionPolicy.RUNTIME)\n  @Documented\n  @Auto\n  public @interface Log {\n  }\n\n  \n  //自己实现AnnotationAdapter接口同时使用@Bean标注 .例如\n  @Bean\n  public class MyAutoAnnotationAdapter implements AnnotationAdapter {\n  \n    @Override\n    public void before(Annotation annotation, Object[] args, Class clazz, Method method) {\n  \n      System.out.println(annotation);\n      System.out.println(args.length);\n      if (args.length \u0026gt; 0) {\n        System.out.println(args[0]);\n      }\n      System.out.println(clazz);\n    }\n    \n    @Override\n    public void after(Annotation annotation, Object object, Class clazz, Method method) {\n      System.out.println(object);\n    }\n  }\n\n  \n  //然后你就能这个自己实现的接口中获取到.进行前置后置的处理.\n  //通过参数Annotation 来判断是哪一个注解然后进行相关逻辑处理.\n\u003C/code\u003E\u003C/pre\u003E","2342458":"\u003Cp\u003Eresources文件夹里存放一个banner.txt 里面放入你图标就可以了.\u003C/p\u003E"}}</script>